package com.its.us.web.service.sys;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Sets;
import com.its.us.web.entity.sys.Menu;
import com.its.us.web.entity.sys.Role;
import com.its.us.web.entity.sys.User;
import com.its.us.web.mapper.sys.RoleMapper;
import com.its.us.web.mapper.sys.UserMapper;
import com.its.us.web.service.sys.base.BasePageService;
import com.its.us.web.utils.ConstantsUtil;
import com.its.us.web.utils.JsonUtil;
import com.its.us.web.utils.JwtTokenUtil;
import com.its.us.web.utils.ResponseUtil;
import com.its.us.web.vo.sys.ResultBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author huguangjun
 * @className UserService
 * @date 2020/12/3
 * @desc 9:07
 */
@Transactional(rollbackFor = Exception.class)
@Service
@Slf4j
public class UserService extends BasePageService<User> {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private AuthenticationManager authenticationManager;

    @Resource
    private UserDetailsServiceImpl userDetailsServiceImpl;

    @Resource
    private UserMapper userMapper;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RoleMapper roleMapper;


    /**
     * 系统登录校验
     *
     * @param username
     * @param password
     * @return
     */
    //@Deprecated
    public Map login(String username, String password) {
        Map<String, Object> map = new HashMap<>();
        try {
            User user = userDetailsServiceImpl.getUserByName(username);
            if (user == null) {
                map.put("code", 404);
                map.put("msg", "用户不存在.");
                return map;
            }

            UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(username);
            if (!(new BCryptPasswordEncoder().matches(password, userDetails.getPassword()))) {
                map.put("code", 403);
                map.put("msg", "密码错误.");
                return map;
            }

            Authentication token = new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities());
            Authentication authentication = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);

            final String realToken = jwtTokenUtil.generateToken(userDetails);
            List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities();
            List<String> perms = new ArrayList<>();
            authorities.forEach(perm ->
                    perms.add(perm.getAuthority())
            );
            map.put("code", 200);
            map.put("sub", user.getUsername());
            map.put("msg", "登录成功.");
            map.put(ConstantsUtil.Token.TOKEN_NAME, realToken);
            // 页面可控制按钮显示与否
            map.put(ConstantsUtil.Button.BUTTON_PERMISSION, perms);
        } catch (DisabledException e1) {
            map.put("code", 401);
            map.put("msg", "登录账号被禁用.");
            log.error("登录账号[" + username + "]被禁用：", e1);
        } catch (Exception ef) {
            log.error("登录错误：", ef);
        }
        return map;
    }


    /**
     * 账户列表
     *
     * @param map
     * @return
     */
    public IPage<User> findByPage(Map<String, Object> map) {
        //设置查询条件
        QueryWrapper<User> wrapper = new QueryWrapper();
        /*int page = Integer.parseInt(map.get("page").toString());
        int rows = Integer.parseInt(map.get("rows").toString());
        // 第一个参数：页码，第二个参数：每页多少行
        IPage<User> pageInfo = new Page<>(page, rows);*/
        IPage<User> pageInfo = initPage(map);
        wrapper.select("id", "username", "is_enabled");
        Iterator its = map.entrySet().iterator();

        // 封装
        while (its.hasNext()) {
            Map.Entry entry = (Map.Entry) its.next();
            String key = entry.getKey().toString();
            if (key.equals("userName")) {
                wrapper.like("username", entry.getValue());
            }
        }
        IPage<User> list = userMapper.selectPage(pageInfo, wrapper.orderByDesc("id"));
        return list;
    }

    /**
     * save or update obj
     *
     * @param user
     * @return
     */
    public ResultBean saveOrUpdate(User user) {
        QueryWrapper<User> wrapper = new QueryWrapper();
        // update
        if (StringUtils.isNotEmpty(user.getId())) {
            wrapper.eq("id", user.getId());
            User obj = userMapper.selectOne(wrapper);
            if (null != obj) {
                User entity = new User();
                if (StringUtils.isNotEmpty(user.getPassword())) {
                    String password = user.getPassword();
                    entity.setPassword(passwordEncoder.encode(password));
                    // 参数：值和条件
                    userMapper.update(entity, wrapper);
                    return new ResultBean("操作成功.");
                }
            } else {
                // 数据异常
                return new ResultBean("数据异常.");
            }
        } else {
            // insert
            User obj = this.checkUserName(user);
            if (null != obj) {
                // 数据已经存在
                return new ResultBean("数据账户已存在.");
            } else {
                // 加密密码
                String password = passwordEncoder.encode(user.getPassword());
                user.setPassword(password);
                userMapper.insert(user);
                return new ResultBean("操作成功.");
            }
        }
        return new ResultBean("数据标识已存在.");
    }

    /**
     * private method
     * for en find user obj
     *
     * @param user
     * @return
     */
    private User checkUserName(User user) {
        User obj = null;
        QueryWrapper<User> wrapper = new QueryWrapper();
        if (StringUtils.isNotEmpty(user.getUsername())) {
            wrapper.eq("username", user.getUsername());
            obj = userMapper.selectOne(wrapper);
        }
        return obj;
    }

    /**
     * 详情
     *
     * @param id
     * @return
     */
    public User findById(String id) {
        User user = userMapper.selectById(id);
        // clear
        user.setPassword("");
        return user;
    }

    /**
     * 删除
     * 注意：不能删除自身
     *
     * @param ids
     * @param userName
     * @return
     */
    public ResultBean deleteByIds(List<String> ids, String userName) throws Exception {
        User user = userMapper.getUserByNameNotPassword(userName);
        // set has userId
        Set<String> hasIds = new HashSet<>(Arrays.asList(user.getId()));
        // set params ids
        Set<String> paramIds = new HashSet<>(ids);
        // diff,because don't delete self
        Sets.SetView<String> diffSetIds = Sets.symmetricDifference(hasIds, paramIds);
        // set toList
        List<String> listIds = new ArrayList<>(diffSetIds);
        // filter has ids
        for (int i = 0; i < listIds.size(); i++) {
            if (user.getId().equals(listIds.get(i))) {
                listIds.remove(i);
            }
        }
        // delete about sys_user
        if (listIds.size() > 0) {
            userMapper.deleteBatchIds(listIds);
            // delete sys_user_role
            roleMapper.deleteUserRoleByRoleIds(listIds);
            // test transactional
            //System.out.println(1/0);
        }
        return new ResultBean("操作成功.");
    }

    /**
     * user auth role
     *
     * @param roleIds
     * @param userId
     * @return
     */
    public ResultBean authRole(List<String> roleIds, String userId) throws Exception {
        if (roleIds.size() > 0) {
            // delete
            roleMapper.deleteUserRole(userId);
            // add
            for(int i=0;i<roleIds.size();i++){
                // clear user role
                if(!roleIds.get(i).equals(ConstantsUtil.System.AUTH_NULL)){
                    roleMapper.insertUserRole(roleIds.get(i), userId);
                }
            }

        }
        return new ResultBean("操作成功.");
    }
}
